home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / minix / up1510b.tgz / up1510b / src / commands / whatsnew.c < prev    next >
C/C++ Source or Header  |  1990-07-19  |  6KB  |  260 lines

  1. /* whatsnew - mark changes in a patched file    Author: Andy Tanenbaum */
  2.  
  3. /* MINIX programs are constantly being updated.  When a cdiff patch comes in,
  4.  * it would be nice to be able to apply the patch, and then list the new file,
  5.  * which the changed lines marked somehow.  This program allows that.  Suppose
  6.  * prog.c is the newly patched file and prog.cdif is the cdiff listing that was
  7.  * used to produce it.  Then the command
  8.  *
  9.  *     whatsnew prog.c prog.cdif
  10.  *
  11.  * will copy prog.c to standard output, marking all added or changed lines
  12.  * with + or ! at the end, respectively.  Output lines are forced to a standard
  13.  * length to make the + and ! symbols easy to find.  The default length is 80,
  14.  * but it can be changed using a flag.  For example,
  15.  *
  16.  *    whatsnew -75 prog.c prog.cdif
  17.  *
  18.  * which pads or truncates the output lines to 75 characters before appending
  19.  * ! or +.  Tabs are converted to spaces in the process.
  20.  */
  21.  
  22. #include <stdio.h>
  23.  
  24. #define MAX_WIDTH       256    /* max line length */
  25. #define HEAP_LINES    10000    /* max length of the diff listing */
  26. #define HEAP_BYTES    30000    /* total space for saved lines */
  27. #define HASH_SIZE        10    /* how much of a line is the hash key */
  28. #define TAB_WIDTH         8    /* how far apart are the tab stops */
  29. #define DEF_WIDTH        80    /* default width */
  30.  
  31. int cdif_found = 0;        /* set to 1 if cdif entry found */
  32. char *index[HEAP_LINES];    /* pointers into the heap */
  33. char heap[HEAP_BYTES];        /* the + and ! lines are saved here. */
  34. int lines_used;            /* number of index slots used */
  35. char *hp = heap;        /* pointer to end of the heap */
  36. int width = DEF_WIDTH;        /* how wide to print the listing */
  37.  
  38. main(argc, argv)
  39. int argc;
  40. char *argv[];
  41. {
  42.  
  43.   int k;
  44.   char *p;
  45.   FILE *newf, *cdif;
  46.  
  47.   /* Process the command line. */
  48.   if (argc < 2) usage();
  49.  
  50.   k = 1;
  51.   p = argv[1];
  52.   if (*p == '-') {
  53.     width = atoi(p + 1);
  54.     if (width < 0 || width > MAX_WIDTH) {
  55.         fprintf(stderr, "%s: max line size is %d\n",argv[0],MAX_WIDTH);
  56.         exit(1);
  57.     }
  58.     k++;
  59.     if (argc != 4) usage();
  60.   } else {
  61.     if (argc != 3) usage();
  62.   }
  63.  
  64.   newf = fopen(argv[k], "r");
  65.   if (newf == NULL) {
  66.     fprintf(stderr, "%s: cannot open %s\n", argv[0], argv[k]);
  67.     exit(1);
  68.   }
  69.   cdif = fopen(argv[k + 1], "r");
  70.   if (cdif == NULL) {
  71.     fprintf(stderr, "%s: cannot open %s\n", argv[0], argv[k + 1]);
  72.     exit(1);
  73.   }
  74.  
  75.   /* Read the cdif file and hash all the relevant lines. */
  76.   eat_cdif(cdif, argv[k]);
  77.  
  78.   /* Read and print the new file. */
  79.   read_and_print(newf, width);
  80.  
  81.   exit(0);
  82. }
  83.  
  84. eat_cdif(cdif, name)
  85. FILE *cdif;
  86. char *name;
  87. {
  88.   int n;
  89.   char line[MAX_WIDTH], *p;
  90.  
  91.   /* First find the start of the relevant cdif stuff. */
  92.   while (fgets(line, MAX_WIDTH, cdif) != NULL) {
  93.     if (strncmp(line, "*** ", 4) != 0) continue;
  94.     if (present(line, name) && present(line, ":")) {
  95.         cdif_found = 1;
  96.         break;
  97.     }
  98.   }
  99.   if (cdif_found == 0) {
  100.     fprintf(stderr, "no cdif found for %s\n", name);
  101.     exit(2);
  102.   }
  103.  
  104.   /* We found it. Save all the ! and + lines in the hash table. */
  105.   while (fgets(line, MAX_WIDTH, cdif) != NULL) {
  106.     if (strcmp(line, "*** ", 4) == 0 && present(line, ":")) break;
  107.     if (line[0] != '+' && line[0] != '!') continue;
  108.     if (line[1] != ' ') continue;
  109.     enter_line(line);
  110.   }
  111. }
  112.  
  113.  
  114. read_and_print(newf)
  115. FILE *newf;
  116. {
  117.   int h, hit;
  118.   char line[MAX_WIDTH], *p, c;
  119.  
  120.   /* Examine each line in the patched file. */
  121.   while (fgets(line, MAX_WIDTH, newf) != NULL) {
  122.     /* Hash the line and see if it is in the table. */
  123.     hit = -1;
  124.     h = hash(line);
  125.     while (index[h] != 0) {
  126.         if (strcmp(line, index[h] + 2) == 0) {
  127.             hit = h;
  128.             break;
  129.         }
  130.         h = (h + 1) % HEAP_LINES;
  131.     }
  132.     c = (hit >= 0 ? *(index[h]) : ' ');
  133.     print_line(line, c);
  134.   }
  135. }
  136.  
  137.  
  138. int present(line, name)
  139. char *line, *name;
  140. {
  141. /* Scan line to see if the string name is present in it anywhere.  If so,
  142.  * return 1, else return 0.
  143.  */
  144.  
  145.   register int n;
  146.   register char *p;
  147.  
  148.   p = line;
  149.   n = strlen(name);
  150.   while (*p != 0) {
  151.     if (strncmp(p, name, n) == 0) return(1);
  152.     p++;
  153.   }
  154.   return(0);
  155. }
  156.  
  157.  
  158. enter_line(line)
  159. char *line;
  160. {
  161. /* Enter a line in the hash table.  Note that the first two characters
  162.  * do not count, as they have been added by cdiff.
  163.  */
  164.  
  165.   int n, h;
  166.  
  167.   /* Certain lines should not be entered as they occur often. */
  168.   n = strlen(line) - 2;
  169.   if (n == 1) return;        /* don't enter null lines */
  170.   if (strncmp(line, "+ /*==", 6) == 0) return;
  171.   if (strncmp(line, "+  *==", 6) == 0) return;
  172.   if (strncmp(line, "+   {", 5) == 0) return;
  173.   if (strncmp(line, "+   }", 5) == 0) return;
  174.   if (strncmp(line, "+ {", 3) == 0) return;
  175.   if (strncmp(line, "+ }", 3) == 0) return;
  176.   if (strncmp(line, "+ \t{", 4) == 0) return;
  177.   if (strncmp(line, "+ \t}", 4) == 0) return;
  178.   if (strncmp(line, "+ else", 6) == 0) return;
  179.   if (strncmp(line, "+ #end", 6) == 0) return;
  180.  
  181.   if (lines_used == HEAP_LINES) {
  182.     fprintf(stderr, "cdif listing has too many lines\n");
  183.     exit(1);
  184.   }
  185.   if (hp + n >= &heap[HEAP_BYTES]) {
  186.     fprintf(stderr, "cdif listing has too many bytes\n");
  187.     exit(1);
  188.   }
  189.  
  190.   /* Make the heap entry. */
  191.   h = hash(line + 2);
  192.   while (index[h] != 0) h = (h + 1) % HEAP_LINES;
  193.   index[h] = hp;        /* index table points to the lines */
  194.   strcpy(hp, line);        /* first two chars also copied */
  195.   lines_used++;            /* count # table slots used */
  196.   hp += n + 3;            /* 0 byte counts also */
  197. }
  198.  
  199.  
  200. int hash(p)
  201. char *p;
  202. {
  203. /* Compute and return the hash code of p. */
  204.  
  205.   int i, n;
  206.   unsigned h;
  207.  
  208.   n = strlen(p);
  209.   if (n > HASH_SIZE) n = HASH_SIZE;
  210.   h = 0;
  211.   for (i = 0; i < n; i++) {
  212.     h += 23 * i * (int) *p;
  213.     p++;
  214.   }
  215.   h = h % HEAP_LINES;
  216.   return((int) h);
  217. }
  218.  
  219.  
  220. print_line(line, c)
  221. char *line, c;
  222. {
  223. /* Print the line. */
  224.  
  225.   int col, spaces;
  226.   char out_buf[3 * MAX_WIDTH], *p, *q;
  227.  
  228.   p = line;
  229.   q = out_buf;
  230.   col = 0;
  231.   while (*p != '\n') {
  232.     /* This loop executed once for each character in the line. */
  233.     if (*p != '\t') {
  234.         /* Not a tab. */
  235.         *q++ = *p++;
  236.         col++;
  237.     } else {
  238.         /* Tab. */
  239.         spaces = TAB_WIDTH - (col % TAB_WIDTH);
  240.         col += spaces;
  241.         while (spaces--) *q++ = ' ';
  242.         p++;
  243.     }
  244.   }
  245.   while (q < &out_buf[width]) *q++ = ' ';
  246.   q = &out_buf[width];
  247.   *q++ = ' ';
  248.   *q++ = c;
  249.   *q++ = '\n';
  250.   *q = 0;
  251.   fputs(out_buf, stdout);
  252. }
  253.  
  254.  
  255. usage()
  256. {
  257.   fprintf(stderr, "Usage: whatsnew [-<width>] file file.cdif\n");
  258.   exit(1);
  259. }
  260.